libxl_free_all(ctx);
free(ctx->alloc_ptrs);
xc_interface_close(ctx->xch);
- xs_daemon_close(ctx->xsh);
+ if (ctx->xsh) xs_daemon_close(ctx->xsh);
return 0;
}
int libxl_ctx_init(struct libxl_ctx *ctx, int version);
int libxl_ctx_free(struct libxl_ctx *ctx);
int libxl_ctx_set_log(struct libxl_ctx *ctx, libxl_log_callback log_callback, void *log_data);
+int libxl_ctx_postfork(struct libxl_ctx *ctx);
/* domain related functions */
int libxl_domain_make(struct libxl_ctx *ctx, libxl_domain_create_info *info, uint32_t *domid);
void (*intermediate_hook)(void *for_spawn, pid_t innerchild));
/* Logs errors. A copy of "what" is taken. Return values:
* < 0 error, for_spawn need not be detached
- * +1 caller is now the inner child, should probably call libxl_exec
- * 0 caller is the parent, must call detach on *for_spawn eventually
+ * +1 caller is the parent, must call detach on *for_spawn eventually
+ * 0 caller is now the inner child, should probably call libxl_exec
* Caller, may pass 0 for for_spawn, in which case no need to detach.
*/
int libxl_spawn_detach(struct libxl_ctx *ctx,
READ_WRITE_EXACTLY(write, 0, const)
+int libxl_ctx_postfork(struct libxl_ctx *ctx) {
+ if (ctx->xsh) xs_daemon_destroy_postfork(ctx->xsh);
+ ctx->xsh = xs_daemon_open();
+ if (!ctx->xsh) return ERROR_FAIL;
+ return 0;
+}
+
pid_t libxl_fork(struct libxl_ctx *ctx)
{
pid_t pid;
return -1;
}
+ if (!pid) {
+ if (ctx->xsh) xs_daemon_destroy_postfork(ctx->xsh);
+ ctx->xsh = 0;
+ /* This ensures that anyone who forks but doesn't exec,
+ * and doesn't reinitialise the libxl_ctx, is OK.
+ * It also means they can safely call libxl_ctx_free. */
+ }
+
return pid;
}
return get_handle(xs_domain_dev());
}
-void xs_daemon_close(struct xs_handle *h)
-{
+static void close_free_msgs(struct xs_handle *h) {
struct xs_stored_msg *msg, *tmsg;
+ list_for_each_entry_safe(msg, tmsg, &h->reply_list, list) {
+ free(msg->body);
+ free(msg);
+ }
+
+ list_for_each_entry_safe(msg, tmsg, &h->watch_list, list) {
+ free(msg->body);
+ free(msg);
+ }
+}
+
+static void close_fds_free(struct xs_handle *h) {
+ if (h->watch_pipe[0] != -1) {
+ close(h->watch_pipe[0]);
+ close(h->watch_pipe[1]);
+ }
+
+ close(h->fd);
+
+ free(h);
+}
+
+void xs_daemon_destroy_postfork(struct xs_handle *h)
+{
+ close_free_msgs(h);
+ close_fds_free(h);
+}
+
+void xs_daemon_close(struct xs_handle *h)
+{
mutex_lock(&h->request_mutex);
mutex_lock(&h->reply_mutex);
mutex_lock(&h->watch_mutex);
}
#endif
- list_for_each_entry_safe(msg, tmsg, &h->reply_list, list) {
- free(msg->body);
- free(msg);
- }
-
- list_for_each_entry_safe(msg, tmsg, &h->watch_list, list) {
- free(msg->body);
- free(msg);
- }
+ close_free_msgs(h);
mutex_unlock(&h->request_mutex);
mutex_unlock(&h->reply_mutex);
mutex_unlock(&h->watch_mutex);
- if (h->watch_pipe[0] != -1) {
- close(h->watch_pipe[0]);
- close(h->watch_pipe[1]);
- }
-
- close(h->fd);
-
- free(h);
+ close_fds_free(h);
}
static bool read_all(int fd, void *data, unsigned int len)
/* Close the connection to the xs daemon. */
void xs_daemon_close(struct xs_handle *);
+/* Throw away the connection to the xs daemon, for use after fork(). */
+void xs_daemon_destroy_postfork(struct xs_handle *);
+
/* Get contents of a directory.
* Returns a malloced array: call free() on it after use.
* Num indicates size.